<?php
/**
 * Класс для обработки ошибок (exception).
 *
 * Подразумевается, что класс обрабатывает только ошибки PHP
 *
 *
 * 
 *
 */
class Errors
{
	// если ошибка этого уровня - прекращаем работу скрипта
   	var $exit_level		= E_ALL;

	/**
	 * Урвоень ошибки, при котором её нужно записывать в лог-файл
	 * @var int
	 */ 
   	public $log_level		= E_ALL;

   	/**
   	 *  Уровень ошибки, при котором нужно отправлять уведомление на e-mail
   	 *  @var int
   	 */
	public $mail_level		= E_ALL;
   	
   	/**
   	 * Имя функции для логирования ошибок
     * Если не задана или не существует - будет использованая функция error_log()
     * В функция передаётся один параметр - сообщение об ошибки
   	 *
   	 * @var string
   	 */
	var $log_function	= NULL;

	/**
	 * Имя функции для отправляения ошибки на емайл
	 * 
	 * @var string
	 */
	public $mail_function	= NULL;

	/**
	 * Адрес на который нужно отправлять ошибки
	 * @var string
	 */
	public $mail_addresses	= NULL;


	/**
	 * Массив ошибок
	 * @var <unknown_type>
	 */
	private $errors=array();

	function __construct()
	{
		
	}

	/**
	 * Навешивает обработчики ошибок
	 * 
	 * @return void
	 */
	public function Setup()
	{
		// навешиваем свою функцию обработчика ошибок
		set_error_handler( array($this,'ErrorHandler') );

		// навешиваем свою функцию, которая отработаем по завершению программы
		register_shutdown_function( array($this,'ShutdownFunction') );
	}


	/**
	 * Оброботчик ошибок, вызывается каждый раз когда происходит ошибка
	 * 
	 * @see http://php.net/manual/en/function.set-error-handler.php
	 * 
	 * @param int $errno
	 * @param string $errstr
	 * @param string $file
	 * @param int $line
	 * @return void
	 */
	function ErrorHandler( $errno, $errstr, $file, $line )
	{
		$error=array(
			'errno'	=> &$errno,
			'errstr'=> &$errstr,
			'file'	=> &$file,
			'line'	=> &$line,
			'backtrace'=> $this->GetTrace(),
		);
		$this->errors[]=$error;

		// получаем ошибку в виде строки
		$message=$this->ToString( $error );
	
	    // проверяем нужно-ли печатать ошибку
		$error_reporting = error_reporting();
		if ( $error_reporting & $errno )
		{
			//print $message."\n";
			print $this->ToHtml( &$error );
		}

		// проверяем нужно-ли логировать ошибку
	    if ( $errno & $this->log_level )
	    {
		    if ( $this->log_function && function_exists($this->log_function) )
			    call_user_func( $this->log_function, trim($message) );
			else
				error_log( trim($message) );
		}

		// проверяем нужно-ли после этой ошибки закончить выпоплнение программы
		if ( $errno & $this->exit_level )
		{
			exit();
		}
	}

	function ToString( $error, $format="%errname%: %errstr% in %file% as %line%\n%trace%" )
	{
		$errors=array(
			1=>'E_ERROR',2=>'E_WARNING',8=>'E_NOTICE',
			256=>'E_USER_ERROR',512=>'E_USER_WARNING',1024=>'E_USER_NOTICE',
			2048=>'E_STRICT',8192=>'E_DEPRECATED',
		);

		$message= strtr($format,array(
			'%errname%'	=> ( empty($errors[$error['errno']]) ? "E_UNKNOWN (".$error['errno'].")" : $errors[$error['errno']] ),
			'%errno%'	=> $error['errno'],
			'%errstr%'	=> $error['errstr'],
			'%file%'	=> $error['file'],
			'%line%'	=> $error['line'],
		));

		$trace=array();
		foreach ( $error['backtrace'] as $k=>$v )
		{
			$trace[]=sprintf(
				"\t%s->%s in %s at %s",
				$v['class'],
				$v['function'],
				$v['file'],
				$v['line']
			);
		}
		
		$message = strtr($message,array(
			'%trace%'	=> join("\n",$trace)
		));

		return $message;
	}

	function ToHtml( $error )
	{
		return $this->ToString( $error, "<pre><b>%errname%: %errstr%</b> in %file% as %line%<br/>%trace%</pre>" );
	}

	function GetTrace()
	{
		$trace = array();
		$backtrace = debug_backtrace();
		array_shift($backtrace);
		array_shift($backtrace);

		foreach ( $backtrace as $k=>$v )
		{
			$trace[]=array(
				'file'		=> empty($v['file']) ? '' : $v['file'],
				'line'		=> empty($v['line']) ? '' : $v['line'],
				'class'		=> empty($v['class']) ? '' : $v['class'],
				'function'	=> empty($v['function']) ? '' : $v['function'],
			);
		}
		return $trace;

	}

	/**
	 * Вызывается в момент остановки скрипта, и при необходимости отправляет ошибки
	 * @return unknown_type
	 */
	function ShutdownFunction()
	{

		$body	= '';
		$emails	= explode(",",$this->mail_addresses);
		$subject= '';
		$header	= '';

		foreach ( $this->errors as $error )
		{
			if ( $error['errno'] & $this->mail_level )
			{
				$body.=$this->ToString( $error )."\n--------------\n";
			}
		}
		if ( $body )
		{
			foreach ($emails as $email)
			{	
				mail($email,$subject,$body,$header);	
			}
		}
	}

}

?>